#include <easy3d/algo/tessellator.h>
#include <easy3d/core/polygon.h>

#include <memory>
#include <vector>

#include <pybind11/pybind11.h>
#include <pybind11/stl.h>


#ifndef BINDER_PYBIND11_TYPE_CASTER
	#define BINDER_PYBIND11_TYPE_CASTER
	PYBIND11_DECLARE_HOLDER_TYPE(T, std::shared_ptr<T>, false)
	PYBIND11_DECLARE_HOLDER_TYPE(T, T*, false)
	PYBIND11_MAKE_OPAQUE(std::shared_ptr<void>)
#endif

void bind_easy3d_algo_tessellator(pybind11::module_& m)
{

    { // easy3d::Tessellator file:easy3d/algo/tessellator.h line:56
        pybind11::class_<easy3d::Tessellator, std::shared_ptr<easy3d::Tessellator>> cl(m, "Tessellator", "Tessellator subdivides concave planar polygons, polygons with holes, or polygons with intersecting edges\n into triangles or simple contours. \n\n\n \n\n\n This implementation is also able to keep track of the unique vertices and respective indices, which allows to\n take advantage of the element buffer for efficient rendering (i.e., avoid sending vertices with the same\n geometry to the GPU).\n \n\n\n Typical applications:\n   - Tessellate concave polygons, polygons with holes, or polygons with intersecting edges;\n   - Generate buffer data for rendering;\n   - Triangulate non-triangle surfaces;\n   - Stitch patches of a triangle meshes;\n   - CSG operations\n  \n\n\n   - csg::tessellate(std::vector<Polygon2> &polygons, Tessellator::WindingRule rule);\n   - csg::union_of(std::vector<Polygon2> &polygons);\n   - csg::intersection_of(const Polygon2& polygon_a, const Polygon2& polygon_b, std::vector<Polygon2> &result);\n   - csg::difference_of(const Polygon2& polygon_a, const Polygon2& polygon_b, std::vector<Polygon2> &result).");
        cl.def( pybind11::init( [](){ return new easy3d::Tessellator(); } ) );
        cl.def( pybind11::init( [](easy3d::Tessellator const &o){ return new easy3d::Tessellator(o); } ) );

        pybind11::enum_<easy3d::Tessellator::WindingRule>(cl, "WindingRule", pybind11::arithmetic(), "The winding rule (default rule is ODD, modify if needed)")
                .value("WINDING_ODD", easy3d::Tessellator::WINDING_ODD)
                .value("WINDING_NONZERO", easy3d::Tessellator::WINDING_NONZERO)
                .value("WINDING_POSITIVE", easy3d::Tessellator::WINDING_POSITIVE)
                .value("WINDING_NEGATIVE", easy3d::Tessellator::WINDING_NEGATIVE)
                .value("WINDING_ABS_GEQ_TWO", easy3d::Tessellator::WINDING_ABS_GEQ_TWO)
                .export_values();

        cl.def("set_boundary_only", (void (easy3d::Tessellator::*)(bool)) &easy3d::Tessellator::set_boundary_only, "Set the working mode of the tessellator.\n \n\n The tessellator has two working modes and this function sets its working mode.\n The two working modes:\n  - Filled polygons: complex polygons are tessellated into filled polygons;\n  - Boundary only: complex polygons are tessellated into simple line loops separating the polygon interior\n                   and exterior\n  \n\n true for the boundary only mode and false for the filled polygons mode.\n\nC++: easy3d::Tessellator::set_boundary_only(bool) --> void", pybind11::arg("b"));
        cl.def("set_winding_rule", (void (easy3d::Tessellator::*)(enum easy3d::Tessellator::WindingRule)) &easy3d::Tessellator::set_winding_rule, "Set the wining rule. The new rule will be effective until being changed by calling this function again.\n With the winding rules, complex CSG operations can be implemented:\n  - UNION: Draw all input contours as a single polygon. The winding number of each resulting region is the\n           number of original polygons that cover it. The union can be extracted by using the WINDING_NONZERO\n           or WINDING_POSITIVE winding rules. Note that with the WINDING_NONZERO winding rule, we would get\n           the same result if all contour orientations were reversed.\n  - INTERSECTION: This only works for two contours at a time. Draw a single polygon using two contours.\n           Extract the result using WINDING_ABS_GEQ_TWO.\n  - DIFFERENCE: Suppose you want to compute A diff (B union C union D). Draw a single polygon consisting of\n           the unmodified contours from A, followed by the contours of B, C, and D, with their vertex order\n           reversed. To extract the result, use the WINDING_POSITIVE winding rule. (If B, C, and D are the\n           result of a BOUNDARY_ONLY operation, an alternative to reversing the vertex order is to reverse\n           the sign of the supplied normal. See begin_polygon().\n Explanation of the winding rule can be found here:\n https://www.glprogramming.com/red/chapter11.html\n\nC++: easy3d::Tessellator::set_winding_rule(enum easy3d::Tessellator::WindingRule) --> void", pybind11::arg("rule"));
        cl.def("begin_polygon", (void (easy3d::Tessellator::*)(const class easy3d::Vec<3, float> &)) &easy3d::Tessellator::begin_polygon, "Begin the tessellation of a complex polygon.\n \n\n This function lets the user supply the polygon normal if known (to improve robustness or to achieve\n        a specific tessellation purpose like CSG). All input data is projected into a plane perpendicular to\n        the normal before tesselation.  All output triangles are oriented CCW with respect to the normal.\n        If the supplied normal is (0,0,0) (the default value), the normal is determined as follows. The\n        direction of the normal, up to its sign, is found by fitting a plane to the vertices, without regard\n        to how the vertices are connected. It is expected that the input data lies approximately in plane;\n        otherwise projection perpendicular to the computed normal may substantially change the geometry. The\n        sign of the normal is chosen so that the sum of the signed areas of all input contours is non-negative\n        (where a CCW contour has positive area).\n \n\n The supplied normal persists until it is changed by another call to this function.\n\nC++: easy3d::Tessellator::begin_polygon(const class easy3d::Vec<3, float> &) --> void", pybind11::arg("normal"));
        cl.def("begin_polygon", (void (easy3d::Tessellator::*)()) &easy3d::Tessellator::begin_polygon, "Begin the tessellation of a complex polygon.\n \n\n This function does not provide the polygon normal and let the tessellator decide.\n\nC++: easy3d::Tessellator::begin_polygon() --> void");
        cl.def("begin_contour", (void (easy3d::Tessellator::*)()) &easy3d::Tessellator::begin_contour, "Begin a contour of a complex polygon (a polygon may have multiple contours).\n\nC++: easy3d::Tessellator::begin_contour() --> void");
        cl.def("add_vertex", (void (easy3d::Tessellator::*)(const struct easy3d::Tessellator::Vertex &)) &easy3d::Tessellator::add_vertex, "Add a vertex of a contour to the tessellator.\n \n\n The vertex data.\n \n\n The index of this vertex. Providing a non-negative index allows to map a resulting vertex to\n            the original vertex. Any new vertex generated in the tessellation will have a negative index -1.\n\nC++: easy3d::Tessellator::add_vertex(const struct easy3d::Tessellator::Vertex &) --> void", pybind11::arg("data"));
        cl.def("add_vertex", [](easy3d::Tessellator &o, const float * a0, unsigned int const & a1) -> void { return o.add_vertex(a0, a1); }, "", pybind11::arg("data"), pybind11::arg("size"));
        cl.def("add_vertex", (void (easy3d::Tessellator::*)(const float *, unsigned int, int)) &easy3d::Tessellator::add_vertex, "C++: easy3d::Tessellator::add_vertex(const float *, unsigned int, int) --> void", pybind11::arg("data"), pybind11::arg("size"), pybind11::arg("idx"));
        cl.def("add_vertex", [](easy3d::Tessellator &o, const class easy3d::Vec<3, float> & a0) -> void { return o.add_vertex(a0); }, "", pybind11::arg("xyz"));
        cl.def("add_vertex", (void (easy3d::Tessellator::*)(const class easy3d::Vec<3, float> &, int)) &easy3d::Tessellator::add_vertex, "C++: easy3d::Tessellator::add_vertex(const class easy3d::Vec<3, float> &, int) --> void", pybind11::arg("xyz"), pybind11::arg("idx"));
        cl.def("add_vertex", [](easy3d::Tessellator &o, const class easy3d::Vec<3, float> & a0, const class easy3d::Vec<2, float> & a1) -> void { return o.add_vertex(a0, a1); }, "", pybind11::arg("xyz"), pybind11::arg("t"));
        cl.def("add_vertex", (void (easy3d::Tessellator::*)(const class easy3d::Vec<3, float> &, const class easy3d::Vec<2, float> &, int)) &easy3d::Tessellator::add_vertex, "C++: easy3d::Tessellator::add_vertex(const class easy3d::Vec<3, float> &, const class easy3d::Vec<2, float> &, int) --> void", pybind11::arg("xyz"), pybind11::arg("t"), pybind11::arg("idx"));
        cl.def("add_vertex", [](easy3d::Tessellator &o, const class easy3d::Vec<3, float> & a0, const class easy3d::Vec<3, float> & a1) -> void { return o.add_vertex(a0, a1); }, "", pybind11::arg("xyz"), pybind11::arg("v1"));
        cl.def("add_vertex", (void (easy3d::Tessellator::*)(const class easy3d::Vec<3, float> &, const class easy3d::Vec<3, float> &, int)) &easy3d::Tessellator::add_vertex, "C++: easy3d::Tessellator::add_vertex(const class easy3d::Vec<3, float> &, const class easy3d::Vec<3, float> &, int) --> void", pybind11::arg("xyz"), pybind11::arg("v1"), pybind11::arg("idx"));
        cl.def("add_vertex", [](easy3d::Tessellator &o, const class easy3d::Vec<3, float> & a0, const class easy3d::Vec<3, float> & a1, const class easy3d::Vec<2, float> & a2) -> void { return o.add_vertex(a0, a1, a2); }, "", pybind11::arg("xyz"), pybind11::arg("v1"), pybind11::arg("t"));
        cl.def("add_vertex", (void (easy3d::Tessellator::*)(const class easy3d::Vec<3, float> &, const class easy3d::Vec<3, float> &, const class easy3d::Vec<2, float> &, int)) &easy3d::Tessellator::add_vertex, "C++: easy3d::Tessellator::add_vertex(const class easy3d::Vec<3, float> &, const class easy3d::Vec<3, float> &, const class easy3d::Vec<2, float> &, int) --> void", pybind11::arg("xyz"), pybind11::arg("v1"), pybind11::arg("t"), pybind11::arg("idx"));
        cl.def("add_vertex", [](easy3d::Tessellator &o, const class easy3d::Vec<3, float> & a0, const class easy3d::Vec<3, float> & a1, const class easy3d::Vec<3, float> & a2) -> void { return o.add_vertex(a0, a1, a2); }, "", pybind11::arg("xyz"), pybind11::arg("v1"), pybind11::arg("v2"));
        cl.def("add_vertex", (void (easy3d::Tessellator::*)(const class easy3d::Vec<3, float> &, const class easy3d::Vec<3, float> &, const class easy3d::Vec<3, float> &, int)) &easy3d::Tessellator::add_vertex, "C++: easy3d::Tessellator::add_vertex(const class easy3d::Vec<3, float> &, const class easy3d::Vec<3, float> &, const class easy3d::Vec<3, float> &, int) --> void", pybind11::arg("xyz"), pybind11::arg("v1"), pybind11::arg("v2"), pybind11::arg("idx"));
        cl.def("add_vertex", [](easy3d::Tessellator &o, const class easy3d::Vec<3, float> & a0, const class easy3d::Vec<3, float> & a1, const class easy3d::Vec<3, float> & a2, const class easy3d::Vec<2, float> & a3) -> void { return o.add_vertex(a0, a1, a2, a3); }, "", pybind11::arg("xyz"), pybind11::arg("v1"), pybind11::arg("v2"), pybind11::arg("t"));
        cl.def("add_vertex", (void (easy3d::Tessellator::*)(const class easy3d::Vec<3, float> &, const class easy3d::Vec<3, float> &, const class easy3d::Vec<3, float> &, const class easy3d::Vec<2, float> &, int)) &easy3d::Tessellator::add_vertex, "C++: easy3d::Tessellator::add_vertex(const class easy3d::Vec<3, float> &, const class easy3d::Vec<3, float> &, const class easy3d::Vec<3, float> &, const class easy3d::Vec<2, float> &, int) --> void", pybind11::arg("xyz"), pybind11::arg("v1"), pybind11::arg("v2"), pybind11::arg("t"), pybind11::arg("idx"));
        cl.def("end_contour", (void (easy3d::Tessellator::*)()) &easy3d::Tessellator::end_contour, "Finish the current contour of a polygon.\n\nC++: easy3d::Tessellator::end_contour() --> void");
        cl.def("end_polygon", (void (easy3d::Tessellator::*)()) &easy3d::Tessellator::end_polygon, "Finish the current polygon.\n\nC++: easy3d::Tessellator::end_polygon() --> void");
        cl.def("vertices", (const class std::vector<struct easy3d::Tessellator::Vertex *> & (easy3d::Tessellator::*)() const) &easy3d::Tessellator::vertices, "The list of vertices in the result.\n\nC++: easy3d::Tessellator::vertices() const --> const class std::vector<struct easy3d::Tessellator::Vertex *> &", pybind11::return_value_policy::automatic);
        cl.def("elements", (const class std::vector<class std::vector<unsigned int> > & (easy3d::Tessellator::*)() const) &easy3d::Tessellator::elements, "The list of elements (triangle or contour) created over many calls. Each element is represented by\n its vertex indices.\n\nC++: easy3d::Tessellator::elements() const --> const class std::vector<class std::vector<unsigned int> > &", pybind11::return_value_policy::automatic);
        cl.def("num_elements_in_polygon", (unsigned int (easy3d::Tessellator::*)() const) &easy3d::Tessellator::num_elements_in_polygon, "The number of elements (triangle or contour) in the last polygon.\n \n\n must be used after call to end_polygon() and before the next call to begin_polygon().\n\nC++: easy3d::Tessellator::num_elements_in_polygon() const --> unsigned int");
        cl.def("reset", (void (easy3d::Tessellator::*)()) &easy3d::Tessellator::reset, "Clear all recorded data (triangle list and vertices) and restart index counter.\n This function is useful if you want to selectively stitch faces/components. In this case, call reset()\n before you process each set. Then for each set, you collect the vertices and vertex indices of the triangles.\n\nC++: easy3d::Tessellator::reset() --> void");
        cl.def("assign", (class easy3d::Tessellator & (easy3d::Tessellator::*)(const class easy3d::Tessellator &)) &easy3d::Tessellator::operator=, "C++: easy3d::Tessellator::operator=(const class easy3d::Tessellator &) --> class easy3d::Tessellator &", pybind11::return_value_policy::automatic, pybind11::arg(""));

        { // easy3d::Tessellator::Vertex file:easy3d/algo/tessellator.h line:59
            auto & enclosing_class = cl;
            //Liangliang: removed "std::vector<double>" to avoid "ImportError: generic_type: type "Vertex" referenced unknown base type "std::__1::vector<double, std::__1::allocator<double>>""
            //pybind11::class_<easy3d::Tessellator::Vertex, std::shared_ptr<easy3d::Tessellator::Vertex>, std::vector<double>> cl(enclosing_class, "Vertex", "A vertex carries both xyz coordinates and its attributes (e.g., color, texcoord). ");
            pybind11::class_<easy3d::Tessellator::Vertex, std::shared_ptr<easy3d::Tessellator::Vertex>> cl(enclosing_class, "Vertex", "A vertex carries both xyz coordinates and its attributes (e.g., color, texcoord). ");
            cl.def( pybind11::init( [](const class easy3d::Vec<3, float> & a0){ return new easy3d::Tessellator::Vertex(a0); } ), "doc" , pybind11::arg("xyz"));
            cl.def( pybind11::init<const class easy3d::Vec<3, float> &, int>(), pybind11::arg("xyz"), pybind11::arg("idx") );

            cl.def( pybind11::init( [](){ return new easy3d::Tessellator::Vertex(); } ), "doc" );
            cl.def( pybind11::init( [](std::size_t const & a0){ return new easy3d::Tessellator::Vertex(a0); } ), "doc" , pybind11::arg("size"));
            cl.def( pybind11::init<std::size_t, int>(), pybind11::arg("size"), pybind11::arg("idx") );

            cl.def( pybind11::init( [](easy3d::Tessellator::Vertex const &o){ return new easy3d::Tessellator::Vertex(o); } ) );
            cl.def_readwrite("index", &easy3d::Tessellator::Vertex::index);
            cl.def("append", (void (easy3d::Tessellator::Vertex::*)(const class easy3d::Vec<3, float> &)) &easy3d::Tessellator::Vertex::append<easy3d::Vec<3, float>>, "C++: easy3d::Tessellator::Vertex::append(const class easy3d::Vec<3, float> &) --> void", pybind11::arg("v"));
            cl.def("assign", (struct easy3d::Tessellator::Vertex & (easy3d::Tessellator::Vertex::*)(const struct easy3d::Tessellator::Vertex &)) &easy3d::Tessellator::Vertex::operator=, "C++: easy3d::Tessellator::Vertex::operator=(const struct easy3d::Tessellator::Vertex &) --> struct easy3d::Tessellator::Vertex &", pybind11::return_value_policy::automatic, pybind11::arg(""));
        }
    }

    // easy3d::csg::tessellate(class std::vector<class easy3d::GenericPolygon<float> > &, enum easy3d::Tessellator::WindingRule) file:easy3d/algo/tessellator.h line:280
    m.def("tessellate", (void (*)(class std::vector<class easy3d::GenericPolygon<float> > &, enum easy3d::Tessellator::WindingRule)) &easy3d::csg::tessellate, "Tessellate a set of polygons of an unknown structure into simple contours according to the winding\n rule. Useful for complex CSG operations.\n The resulting polygons will have the following properties:\n  - free of intersections,\n  - CCW contours define the outer boundary and CW contours define holes.\n \n\n The input polygons, and the result on return.\n  The winding rule to determine the interior and exterior of the complex shape.\n\nC++: easy3d::csg::tessellate(class std::vector<class easy3d::GenericPolygon<float> > &, enum easy3d::Tessellator::WindingRule) --> void", pybind11::arg("polygons"), pybind11::arg("rule"));

    // easy3d::csg::union_of(class std::vector<class easy3d::GenericPolygon<float> > &) file:easy3d/algo/tessellator.h line:286
    m.def("union_of", (void (*)(class std::vector<class easy3d::GenericPolygon<float> > &)) &easy3d::csg::union_of, "Compute the union of a set of polygons.\n \n\n The input polygons, and the result on return.\n\nC++: easy3d::csg::union_of(class std::vector<class easy3d::GenericPolygon<float> > &) --> void", pybind11::arg("polygons"));

}
